
#include <omp.h>
#include <log_util.h>
#include <unistd.h>
#include <sys/stat.h>

static char		*log_filename=NULL;		/* Log filename */
static e_log_level	log_level=log_level_none;	/* Logging level */
static bool		log_date=true;			/* Whether to display date in logs */

static omp_lock_t(ebex_log_lock);
static omp_lock_t(ebex_log_level_lock);



void log_init(e_log_level level, char *fname, bool date)
{
	char *oldfname = NULL;

	omp_init_lock(&ebex_log_lock);
	omp_init_lock(&ebex_log_level_lock);

	omp_set_lock(&ebex_log_lock);
	log_level = level;
	if (fname)
	{
		if (log_filename != fname)
			oldfname = log_filename;
		log_filename = e_strdup(fname);
	}
	log_date = date;
	omp_unset_lock(&ebex_log_lock);

	if (oldfname)
		e_free(oldfname);

	elog(log_level_verbose, "Log started.");
	elog(log_level_debug, "Debug output activated.");

	return;
}


void log_set_level(const e_log_level level)
{
	omp_set_lock(&ebex_log_level_lock);
	log_level = level;
	elog(log_level_verbose, "Log level adjusted to %d.", (int)level);
	omp_unset_lock(&ebex_log_level_lock);

	return;
}


e_log_level log_get_level(void)
{
	return log_level;
}

int
create_parent_dirs(const char *path)
{
        struct stat st;
        int res;
        char *ext = strrchr(path, '/');
        char *parent;

        if (!ext) return 0;

        parent = strndupa(path, (intptr_t)(ext - path));

        if (stat(parent, &st) == 0) {
                if (S_ISDIR(st.st_mode)) {
                        res = 0;
                } else {
                        res = -1;
                        errno = ENOTDIR;
                }
        } else {
                res = create_parent_dirs(parent);
                if (res == 0) {
                        res = mkdir(parent, 0777);
                } else {
                        res = -1;
                }
        }
        return res;
}

void log_set_file(const char *fname)
{
	char *oldfname = NULL;

	omp_set_lock(&ebex_log_lock);
	if (log_filename != fname)
		oldfname = log_filename;
	log_filename = e_strdup(fname);
	if (access(log_filename, W_OK|R_OK))
	{
		create_parent_dirs(log_filename);
	}

	omp_unset_lock(&ebex_log_lock);

	if (oldfname)
		e_free(oldfname);

	elog(log_level_verbose, "Log file adjusted to \"%s\".", fname);

	return;
}


void log_output(const e_log_level level, const char *func_name, const char *file_name, const int line_num,
		const char *format, ...)
{
	va_list ap;
	char message[LOG_MAX_LEN];
	FILE *fp;

	const char *log_text[] =
	{	"?????: ", "FATAL: ", "", "WARNING: ",
		"", "", "",
		"FIXME: ", "DEBUG: "};
	time_t t; /* Time structure */

	t = time(&t); /* Less than optimal when no time display is required. */

	/* Generate actual message string */
	va_start(ap, format);
	vsnprintf(message, LOG_MAX_LEN, format, ap);
	va_end(ap);

	/* Write to file? */
	omp_set_lock(&ebex_log_lock);
	if (log_filename)
	{
		if ( !(fp=fopen(log_filename, "a+")) )
		{
			fprintf(stdout, "FATAL: Unable to open logfile \"%s\" for appending.\n", log_filename);
			abort(); /* FIXME: Find more elegant method */
		}

		if (level >= log_level_fixme)
		fprintf(fp, "%s%s(%s) %s+%d\t",
				log_date?ctime(&t):"", log_date?"":" - ",
				func_name, basename(file_name), line_num);

		fprintf(fp, "%s%s", log_text[level], message);

		fprintf(fp, "\n");
		fclose(fp);
	}
	omp_unset_lock(&ebex_log_lock);

	/* Write to stdout? */
	if ( !log_filename )
	{
		if (level >= log_level_fixme)
		fprintf(stdout, "%s%s(%s) %s+%d\t",
				log_date?ctime(&t):"", log_date?"":" - ",
				func_name, basename(file_name), line_num);

		fprintf(stdout, "%s%s", log_text[level], message);

		fprintf(stdout, "\n");
		fflush(stdout);
	}

	return;
}




